#include "Task.hpp"
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <sys/types.h>
#include <sys/wait.h>

const int processnum = 5;
std::vector<task_t> tasks;
// 因为有大量管道被创建，父进程要管理这些管道，像子进程发送任务
// 为了方便管理，我们先描述，在组织
class channel
{
public:
    channel(int cmdfd, int slaverid, const std::string &processname)
        : _cmdfd(cmdfd), _slaverid(slaverid), _processname(processname)
    {}

public:
    int _cmdfd;
    int _slaverid;
    std::string _processname;
};

void slaver(int rfd)
{
    int cmdcode;
    while (true)
    {
        int n = read(rfd, &cmdcode, sizeof(cmdcode));
        if (n == 0)
            continue;
        // std::cout << getpid() <<" get a message"  << ":" << "cmdcode:" << cmdcode << std::endl;
        // 执行任务
        tasks[cmdcode]();
    }
}

void ProcessInit(std::vector<channel> *channels)
{
    std::vector<int> oldfd;
    taskload(&tasks);
    // 创建多个子进程
    for (int i = 0; i < processnum; i++)
    {
        // 创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        assert(!n);

        // 创建子进程
        pid_t id = fork();
        if (id == 0)
        {
            //关闭所有的子进程从进程那里继承下来的写端
            for(auto& e : oldfd)
            {
                //std::cout << e << " ";
                close(e);
            }
            std::cout << std::endl;
            printf("\n");
            sleep(1);

            // child
            close(pipefd[1]);
            slaver(pipefd[0]);
            exit(0);
        }

        // farther
        std::string name = "process->" + std::to_string(i);
        close(pipefd[0]);
        channels->push_back(channel(pipefd[1], id, name));
        //有个隐藏的bug? 
        //子进程会继承父进程的写端
        oldfd.push_back(pipefd[1]);
    }
}

void menu()
{
    std::cout << "#######################################" << std::endl;
    std::cout << "#1.更新野区和小兵     2.英雄释放技能    #" << std::endl;
    std::cout << "#3.回复英雄血量和蓝量 4.计算英雄复活时间 #" << std::endl;
    std::cout << "#0.exit                               #" << std::endl;
    std::cout << "#######################################" << std::endl;
}
void Debug(const std::vector<channel> &channels)
{
    for (const auto &e : channels)
    {
        std::cout << e._cmdfd << " " << e._slaverid << " " << e._processname << std::endl;
    }
}

void controlprocess(const std::vector<channel> &channels)
{
    // 0.菜单
    menu();
    for (int i = 0; i < 100; i++)
    {
        // 1.选择任务
        //  int cmdcode = rand() % 4;
        int section = 0;
        std::cout << "please Enter@" << " ";
        std::cin >> section;
        if (section <= 0 || section >= 5)  break;

        int cmdcode = section - 1;

        // 2.选择进程(下标)
        //  int n = rand() % channels.size();
        int which = 0;
        which++;
        which %= channels.size();

        // 3.发送任务
        write(channels[which]._cmdfd, &cmdcode, sizeof(cmdcode));
        // std::cout << "farther send a command to " << channels[n]._slaverid << " cmdcode " << cmdcode << std::endl;
        sleep(1);
    }
}

void quitprocess(const std::vector<channel> &channels)
{
    //这种回收的方法完美躲避了隐藏的bug???
    // for (const auto &e : channels)
    // {
    //     close(e._cmdfd);
    // }
    // for (const auto &e : channels)
    // {
    //     waitpid(e._cmdfd, nullptr, 0);
    // }

    for(const auto& e : channels)
    {
        close(e._cmdfd);
        waitpid(e._cmdfd, nullptr, 0);
    }
}

int main()
{
    srand(time(nullptr));
    std::vector<channel> channels;
    ProcessInit(&channels);

    // 测试进程池是否创建成功
    // Debug(channels);

    // 控制子进程
    controlprocess(channels);

    // 清理收尾
    quitprocess(channels);

    //回收成功
    std::cout << "回收成功" << std::endl;
    return 0;
}